<?php
/**
 * @package qBase
 * @subpackage sql
 *
 */

/**
 * QSqlQuery
 * Example
 *
 * 	$q = new QSqlQuery();
 *	
 * 	$q->select()->id->name->{"books.name"}->{"books.id"}->as()->x->
 *
 *			from()->my_books->as()->books->join()->categories->on()->id_categ->eq()->id->
 *
 *			where()->name->like()->val("%123%")->or()->
 *				lb()->active->eq()->val("Yes")->and()->order->gt()->val(0)->rb()->
 *
 *			orderBy()->name->asc()->id->desc();
 * 
 * NOTE : We need to serialize this object so please avoid adding references to $params
 * 
 * @package qBase
 * @subpackage sql
 */
class QSqlQuery
{
	const KeyReserved = 1;
	const KeyVariable = 2;
	const KeyValue = 3;
	
	const OpSelect = 1;
	const OpAs = 2;
	const OpFrom = 3;
	const OpJoin = 4;
	const OpOn = 5;
	const OpEquals = 6;
	const OpWhere = 7;
	const OpLike = 8;
	const OpOr = 9;
	const OpAnd = 10;
	const OpLeftBrachet = 11;
	const OpRightBrachet = 12;
	const OpGreaterThem = 13;
	const OpOrderBy = 14;
	const OpAsc = 15;
	const OpDesc = 16;
	const OpInsert = 17;
	const OpUpdate = 18;
	const OpMerge = 19;
	const OpDelete = 20;
	const OpValues = 21;
	const OpSet = 22;

	public $params = array();
	public $keys = array();

	/**
	 * Generic
	 *
	 * @param string $name
	 * @return QSqlQuery
	 */
	public function __get($name)
	{
		$this->params[] = new QSqlQueryParam(self::KeyVariable, $name);
		return $this;
	}

	/**
	 * Select
	 *
	 * @return QSqlQuery
	 */
	public function select()
	{
		$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpSelect);
		return $this;
	}
	
	/**
	 * Join
	 *
	 * @return QSqlQuery
	 */
	public function join()
	{
		$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpJoin );
		return $this;
	}
	
	/**
	 * On
	 *
	 * @return QSqlQuery
	 */
	public function on()
	{
		$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpOn );
		return $this;
	}
	
	/**
	 * Equals
	 *
	 * @return QSqlQuery
	 */
	public function eq()
	{
		$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpEquals);
		return $this;
	}
	
	/**
	 * Where
	 *
	 * @return QSqlQuery
	 */
	public function where()
	{
		$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpWhere );
		return $this;
	}
	
	/**
	 * Like
	 *
	 * @return QSqlQuery
	 */
	public function like()
	{
		$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpLike );
		return $this;
	}
	
	/**
	 * Left bracket
	 *
	 * @return QSqlQuery
	 */
	public function lb()
	{
		$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpLeftBrachet );
		return $this;
	}
	
	/**
	 * Right bracket
	 *
	 * @return QSqlQuery
	 */
	public function rb()
	{
		$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpRightBrachet );
		return $this;
	}
	
	/**
	 * Greater than
	 *
	 * @return QSqlQuery
	 */
	public function gt()
	{
		$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpGreaterThem );
		return $this;
	}
	
	/**
	 * Order By
	 *
	 * @return QSqlQuery
	 */
	public function orderby()
	{
		$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpOrderBy );
		return $this;
	}
	
	/**
	 * Ascendent
	 *
	 * @return QSqlQuery
	 */
	public function asc()
	{
		$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpAsc );
		return $this;
	}
	
	/**
	 * Descendent
	 *
	 * @return QSqlQuery
	 */
	public function desc()
	{
		$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpDesc );
		return $this;
	}
	
	/**
	 * Insert
	 *
	 * @return QSqlQuery
	 */
	public function insert()
	{
		$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpInsert);
		return $this;
	}
	
	/**
	 * Values
	 *
	 * @return QSqlQuery
	 */
	public function values()
	{
		$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpValues);
		return $this;
	}
	
	/**
	 * Update
	 *
	 * @return QSqlQuery
	 */
	public function update()
	{
		$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpUpdate);
		return $this;
	}
	
	/**
	 * Set
	 *
	 * @return QSqlQuery
	 */
	public function set()
	{
		$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpSet);
		return $this;
	}
	
	/**
	 * Merge
	 *
	 * @return QSqlQuery
	 */
	public function merge()
	{
		$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpMerge);
		return $this;
	}
	
	/**
	 * Delete
	 *
	 * @return QSqlQuery
	 */
	public function delete()
	{
		$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpDelete);
		return $this;
	}
	
	/**
	 * A value
	 *
	 * @return QSqlQuery
	 */
	public function val($data, $key = null)
	{
		if ($key)
		{
			$param = new QSqlQueryParam(self::KeyValue, $data);
			$this->keys[$key] = $param;
			$this->params[] = $param;
			return $this;
		}
		else 
		{
			$this->params[] = new QSqlQueryParam(self::KeyValue, $data);
			return $this;
		}
	}
	
	/**
	 * Sets the keys for the query
	 *
	 * @return QSqlQuery
	 */
	public function setKeys($data)
	{
		foreach ($data as $key => $value)
			$this->keys[$key]->data = $value;
		return $this;
	}
	
	/**
	 * We put here all the functions that are reserved keywords in PHP
	 *
	 * @param string $name
	 * @param array $args
	 * @return QSqlQuery
	 */
	public function __call($name, $args)
	{
		switch (strtolower($name))
		{
			case "as":
				{
					$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpAs);
					return $this;
				}
			case "from":
				{
					$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpFrom );
					return $this;
				}
			case "or":
				{
					$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpOr );
					return $this;
				}
			case "and":
				{
					$this->params[] = new QSqlQueryParam(self::KeyReserved, self::OpAnd );
					return $this;
				}
			default:
				{
					throw new Exception("Unkown operation type : {$name}");
				}
		}
	}
	
	/**
	 * Creates a new query and returns it.
	 *
	 * @return QSqlQuery
	 */
	public static function NewQuery()
	{
		return new QSqlQuery();
	}
	
	
	public function executeQuery(QSqlConnection $conn)
	{
		return $conn->query($this);
	}
	
	public function parseQuery(QSqlConnection $conn)
	{
		return $conn->parseSqlQuery($this);
	}
	
	/**
	 * Creates a query for an update operation
	 * The query will append at the end : WHERE $condition_key = '$condition_value' AND ...
	 * from the $conditions parameters
	 *
	 * @param string $table
	 * @param array $keys_and_values An associative array where the key is the column and the values is the value
	 * @param string $condition_column
	 * @param array $conditions Associative array column = value
	 * @return QSqlQuery
	 */
	public static function GetUpdateQuery($table, $keys_and_values, $conditions)
	{
		$q = new QSqlQuery();
		$q->update()->{$table}->set();

		foreach ($keys_and_values as $key => $value)
			$q->{$key}->eq()->val($value);

		$q->where();
		
		$pos = 0;
		foreach ($conditions as $key => $value)
		{
			if ($pos > 0)
				$q->and();
			$q->{$key}->eq()->val($value);
			$pos++;
		}
		return $q;
	}
	
	/**
	 * Creates a query for an insert operation
	 *
	 * @param string $table
	 * @param array $keys_and_values An associative array where the key is the column and the values is the value
	 * @return QSqlQuery
	 */
	public static function GetInsertQuery($table, $keys_and_values)
	{
		$q = new QSqlQuery();
		$q->insert()->{$table}->lb();

		foreach ($keys_and_values as $key => $value)
			$q->{$key};
			
		$q->rb()->values()->lb();
		
		foreach ($keys_and_values as $key => $value)
			$q->val($value);
			
		$q->rb();
			
		return $q;
	}

	public function serialize()
	{
		return serialize($this->params);
	}
	
	public function unserialize($string)
	{
		$qsql = new QSqlQuery();
		$qsql->params = unserialize($string);
		
		return $qsql;
	}
}


?>